package cn.com.cifi.mars.service.impl;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.list.TreeList;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import cn.com.cifi.mars.bean.dto.EquityValueDto;
import cn.com.cifi.mars.bean.dto.PriceCoreDetailDTO;
import cn.com.cifi.mars.bean.dto.PriceValueDto;
import cn.com.cifi.mars.bean.vo.price.BackTacticsWarnInfoVO;
import cn.com.cifi.mars.bean.vo.price.BulidWarnInfoVO;
import cn.com.cifi.mars.bean.vo.price.BulletinWarnInfoVO;
import cn.com.cifi.mars.bean.vo.price.CoreWarnInfoVO;
import cn.com.cifi.mars.bean.vo.price.PriceApproveWarnInfoVO;
import cn.com.cifi.mars.common.exception.MsgException;
import cn.com.cifi.mars.constant.ApprovedStateCodeEnum;
import cn.com.cifi.mars.constant.BackTacticsEnum;
import cn.com.cifi.mars.constant.CodeEnum;
import cn.com.cifi.mars.constant.CoreWarnItemEnum;
import cn.com.cifi.mars.constant.IsDeleteEnum;
import cn.com.cifi.mars.constant.OperatorTypeEnum;
import cn.com.cifi.mars.constant.OrgTypeEunm;
import cn.com.cifi.mars.constant.ProcessTypeEnum;
import cn.com.cifi.mars.constant.TodoTypeCodeEnum;
import cn.com.cifi.mars.constant.VersionTypeEunm;
import cn.com.cifi.mars.constant.WarnPossitionTypeEnum;
import cn.com.cifi.mars.constant.WhetherEnum;
import cn.com.cifi.mars.entity.ApprovalBill;
import cn.com.cifi.mars.entity.ApprovalPreview;
import cn.com.cifi.mars.entity.ApprovalWarning;
import cn.com.cifi.mars.entity.ApprovalWarningPosition;
import cn.com.cifi.mars.entity.PriceVersion;
import cn.com.cifi.mars.entity.common.IdmUser;
import cn.com.cifi.mars.mapper.mars.ApprovalBillMapper;
import cn.com.cifi.mars.mapper.mars.ApprovalPreviewMapper;
import cn.com.cifi.mars.mapper.mars.ApprovalWarningMapper;
import cn.com.cifi.mars.mapper.mars.ApprovedProjectMapper;
import cn.com.cifi.mars.mapper.mars.PriceCoreDetailMapper;
import cn.com.cifi.mars.mapper.mars.SysProjectFirstMapper;
import cn.com.cifi.mars.service.ApprovalPreviewService;
import cn.com.cifi.mars.service.CommonService;
import cn.com.cifi.mars.util.BasicAuthClient;
import cn.com.cifi.mars.util.LocalDateTimeUtils;
import cn.com.cifi.mars.util.MathUtils;
import cn.com.cifi.mars.util.StrUtils;
import cn.com.cifi.mars.util.UUIDUtils;
import lombok.extern.slf4j.Slf4j;


/**
 * <p>
 * 审批预览表 服务实现类
 * </p>
 *
 * @author JingYuanXiang
 * @since 2020-11-17
 */
@Slf4j
@Service
public class ApprovalPreviewServiceImpl extends ServiceImpl<ApprovalPreviewMapper, ApprovalPreview> implements ApprovalPreviewService {

    @Autowired
    private ApprovalPreviewMapper approvalPreviewMapper;
    
    @Autowired
    private ApprovedProjectMapper approvedProjectMapper;
    
    @Autowired
    private ApprovalBillMapper approvalBillMapper;
    
    @Autowired
    private ApprovalWarningMapper approvalWarningMapper;
    
    @Autowired
	SysProjectFirstMapper sysProjectFirstMapper;
    
    @Autowired
	PriceCoreDetailMapper priceCoreDetailMapper;
    
    @Autowired
    private CommonService commonService;
    
    /**
	 * 数据中台地址
	 */
	@Value("${data_middle_ground_url}")
	private String data_middle_ground_url;
    
    @Value("${investmentloss_url}")
    String investmentloss_url;
    
    @Value("${investment_url}")
    String investment_url;
    
    /**
	 * 数据中心key
	 */
	@Value("${data_api_key}")
	private String data_api_key;
	
	/**
	 * 数据中心value
	 */
	@Value("${data_api_value}")
	private String data_api_value;

    /**
     * 审批预览表
     * @param approvalId 审批id
     * @param content 审批内容
     * @param user 用户
     */
    @Override
    public void saveData(String approvalId, String content, IdmUser user) {
        //参数校验
        if(StringUtils.isBlank(approvalId)) {
            throw new MsgException(CodeEnum.REQUEST_PARAM_NOT_FULL_ERROR);
        }
        //获取审批内容
        ApprovalPreview approvalPreview = approvalPreviewMapper.selectByBillId(approvalId, IsDeleteEnum.NO.getKey());
        if(null != approvalPreview){
            approvalPreview.setContent(content);
            approvalPreview.setUpdateBy(user.getAlias());
            approvalPreview.setUpdateTime(LocalDateTime.now());
            approvalPreview.setIsDelete(IsDeleteEnum.NO.getKey());
            approvalPreviewMapper.updateById(approvalPreview);
        }else {
            approvalPreview = new ApprovalPreview();
            approvalPreview.setId(UUIDUtils.create());
            approvalPreview.setBillId(approvalId);
            approvalPreview.setContent(content);
            approvalPreview.setCreateBy(user.getAlias());
            approvalPreview.setCreateTime(LocalDateTime.now());
            approvalPreview.setUpdateBy(user.getAlias());
            approvalPreview.setUpdateTime(LocalDateTime.now());
            approvalPreview.setIsDelete(IsDeleteEnum.NO.getKey());
            approvalPreviewMapper.insert(approvalPreview);
        }
    }

    /**
     * 获取审批内容
     * @param approvalId 审批id
     * @return
     */
    @Override
    public String getContentByApprovalId(String approvalId) {
        //参数校验
        if(StringUtils.isBlank(approvalId)) {
            throw new MsgException(CodeEnum.REQUEST_PARAM_NOT_FULL_ERROR);
        }
        ApprovalPreview approvalPreview = approvalPreviewMapper.selectByBillId(approvalId, IsDeleteEnum.NO.getKey());
        if(null != approvalPreview){
            return approvalPreview.getContent();
        }
        return null;
    }

	@Override
	public PriceApproveWarnInfoVO getWarnInfo(String projectId, String businessKey) {
		PriceApproveWarnInfoVO vo =  new  PriceApproveWarnInfoVO();
		PriceApproveWarnInfoVO hisObj = null;
		List<BulidWarnInfoVO> bulidWarnInfoList = new ArrayList<>();
		if(StrUtils.isEmpty(businessKey)) {
			String queryDate= LocalDateTimeUtils.getLastByFormat(1, "yyyyMMdd");
			String controlDate= LocalDateTimeUtils.getLastByFormat(1, "yyyyMMdd");
			//投资版取数
			BasicAuthClient bac = new BasicAuthClient();
			String investmentlossUrl = data_middle_ground_url+investmentloss_url+projectId+","+queryDate;
			String investmentlossResult = bac.getData(investmentlossUrl, data_api_key, data_api_value);
			log.info("###投资损溢接口 地址： "+investmentlossUrl);
			log.info("###投资损溢接口 返回数据："+investmentlossResult);
			
			//投资承诺核心指标
			String investmentUrl = data_middle_ground_url+investment_url+queryDate+","+controlDate+","+projectId;
			String investmentResult = bac.getData(investmentUrl, data_api_key, data_api_value);
			log.info("###投资承诺核心指标接口 地址： "+investmentUrl);
			log.info("###投资承诺核心指标接口 返回数据："+investmentResult);
			
			
			//########################本次调价楼栋###############################################
			//获取本次调价提审版本
			List<PriceVersion> priceVersionList = approvedProjectMapper.selectApprovedProject(projectId);
			if (CollectionUtils.isNotEmpty(priceVersionList)){
				//批量调整货值不显示预警相关信息
				int batchAdjust = priceVersionList.get(0).getBatchAdjust();
				if(batchAdjust == 1) {
					return null;
				}
				//判断是否是驳回或是撤回
				ApprovalBill approvalBill = approvalBillMapper.selectApprovalBillByProjectId(projectId,ApprovedStateCodeEnum.NOT_LAUNCHED.getKey(),ProcessTypeEnum.PRICE_MANAGEMENT.getKey());
				if(approvalBill != null) {
					String state = approvalBill.getState();
					 if (!state.equals(ApprovedStateCodeEnum.DELETE.getKey()) &&
		                        !state.equals(ApprovedStateCodeEnum.ENDFLOW.getKey()) &&
		                        !state.equals(ApprovedStateCodeEnum.APPROVAL_SUCCESS.getKey())){
						    String content = approvalPreviewMapper.selectWarnContentByBillId(approvalBill.getId());
							if(StrUtils.isNotEmpty(content)) {
								hisObj = JSON.parseObject(content, PriceApproveWarnInfoVO.class);
							}
					 }
				}
				//过滤只显示动态版、大定价楼栋
				priceVersionList = priceVersionList.stream().filter(s-> s.getVersionType().equals(VersionTypeEunm.DYNAMIC.getKey()) || s.getVersionType().equals(VersionTypeEunm.GETPRICE.getKey())).collect(Collectors.toList());
				if(CollectionUtils.isEmpty(priceVersionList)) {
					return null;
				}
				//调整后各分期楼栋均价
				Map<String, List<PriceValueDto>> bulidAfterMap = new HashMap<>();
	            for(PriceVersion version : priceVersionList) {
	        	   List<PriceValueDto> valueList = approvalPreviewMapper.selectPriceValue(version.getId(),version.getStageName(),OrgTypeEunm.ORG_BUILD.getKey(),IsDeleteEnum.NO.getKey());
	        	   bulidAfterMap.put(version.getProjectfId(), valueList);
	            }
	            
	            //本次调价调整前版本
	            List<String> stageIds = priceVersionList.stream().map(s -> s.getProjectfId()).collect(Collectors.toList());
	            List<PriceVersion> priceVersionBeforeList = approvalPreviewMapper.selectBeforePriceVersionList(stageIds,IsDeleteEnum.NO.getKey());
	            
	            //调整前各分期楼栋均价
				Map<String, List<PriceValueDto>> bulidBeforeMap = new HashMap<>();
				for(PriceVersion version : priceVersionBeforeList) {
	        	   List<PriceValueDto> valueList = approvalPreviewMapper.selectPriceValue(version.getId(),version.getStageName(),OrgTypeEunm.ORG_BUILD.getKey(),IsDeleteEnum.NO.getKey());
	        	   bulidBeforeMap.put(version.getProjectfId(), valueList);
	            }
				
				//本次调价战规版本
				List<PriceVersion> priceVersionStrategyList = approvalPreviewMapper.selectPriceVersionList(stageIds,VersionTypeEunm.WARPLAN.getKey(),"",IsDeleteEnum.NO.getKey());
	            //本次调价各分期楼栋战规均价
				Map<String, List<PriceValueDto>> bulidStrategyMap = new HashMap<>();
				for(PriceVersion version : priceVersionStrategyList) {
	        	   List<PriceValueDto> valueList = approvalPreviewMapper.selectPriceValue(version.getId(),version.getStageName(),OrgTypeEunm.ORG_BUILD.getKey(),IsDeleteEnum.NO.getKey());
	        	   bulidStrategyMap.put(version.getProjectfId(), valueList);
	            }
				
				//本次调价集团审批版本
				List<PriceVersion> priceVersionPresidentList = approvalPreviewMapper.selectPriceVersionPresidentList(stageIds,IsDeleteEnum.NO.getKey());
				//集团审批版本均价
				Map<String, List<PriceValueDto>> bulidPresidentMap = new HashMap<>();
				for(PriceVersion version : priceVersionPresidentList) {
					List<PriceValueDto> valueList = approvalPreviewMapper.selectPresidentPriceValue(version.getId(),version.getStageName(),OrgTypeEunm.ORG_BUILD.getKey(),IsDeleteEnum.NO.getKey());
					bulidPresidentMap.put(version.getProjectfId(), valueList);
				}
				
				int bulidWarnId = 0;
				for(Map.Entry<String,List<PriceValueDto>> entry:bulidAfterMap.entrySet()){
			            String stageId = entry.getKey();
			            List<PriceValueDto> list = entry.getValue();
			            for(PriceValueDto dto : list) {
			            	BulidWarnInfoVO info = new BulidWarnInfoVO();
			            	info.setId(bulidWarnId++);
			            	info.setObjectName(dto.getStageName()+"-"+dto.getBuildName()+"("+dto.getProductName()+"-"+dto.getFreeTypeName()+"-"+dto.getBusinessTypeName()+"-"+dto.getProTypeName()+")");
			            	info.setStrategyAvg(getPriceAvg(stageId,dto.getBuildId(),bulidStrategyMap));
			            	info.setPresidentAvg(getPriceAvg(stageId,dto.getBuildId(),bulidPresidentMap));
			            	info.setBeforeAvg(getPriceAvg(stageId,dto.getBuildId(),bulidBeforeMap));
			            	info.setAfterAvg(dto.getAvg()+"");
			            	info.setIsParking(dto.getIsParking());
			            	info.setIsEdit(dto.getIsEdit());
			            	bulidWarnInfoList.add(info);
			            }
			    }
				//调整后均价与调整前不⼀样的所有楼栋
				for(BulidWarnInfoVO obj : bulidWarnInfoList) {
					obj.setAfterStrategy(getBalance(obj.getAfterAvg(),obj.getStrategyAvg()));
					obj.setAfterPresident(getBalance(obj.getAfterAvg(),obj.getPresidentAvg()));
					obj.setAfterBfore(getBalance(obj.getAfterAvg(),obj.getBeforeAvg()));
					obj.setDivergeRate(calculateBuildAvgDivergeRate(obj,obj.getAfterAvg(),obj.getPresidentAvg(),obj.getStrategyAvg()));
				}
				List<BulidWarnInfoVO> bulidAvgDifferenceList = bulidWarnInfoList.stream().filter(s->compareBuildAvgDiff(s) && isEdit(s.getIsEdit()) ).collect(Collectors.toList());
				vo.setBulidWarnInfoList(bulidAvgDifferenceList);
				
				//########################本次调价楼栋###############################################
				
				//########################本次调价对整盘核心指标影响###############################################
				List<EquityValueDto> priceList = approvalPreviewMapper.selectEquityPrice(projectId,IsDeleteEnum.NO.getKey());
				//集团核心指标
				List<PriceCoreDetailDTO> detailList = priceCoreDetailMapper.selectNewstByProjectId(projectId);
				
				//本次调价对整盘核心指标影响对标版本
				String coreMarsVersion = null;
				if(CollectionUtils.isEmpty(priceVersionPresidentList)) {
					coreMarsVersion = "投资版";
				}else {
					coreMarsVersion = "集团审批版";
				}
				
				int coreWarnId = 0;
				List<CoreWarnInfoVO> coreWarnInfoList = new TreeList();
				CoreWarnInfoVO equityPriceObj = new CoreWarnInfoVO();
				equityPriceObj.setId(coreWarnId++);
				equityPriceObj.setType(CoreWarnItemEnum.EQUITYPRICE.getKey());
				equityPriceObj.setName(CoreWarnItemEnum.EQUITYPRICE.getValue());	
				equityPriceObj.setInvestment(getInvestmentValue(CoreWarnItemEnum.EQUITYPRICE.getKey(),investmentlossResult,hisObj,equityPriceObj));
				equityPriceObj.setStrategy(getEquityValue("strategy",priceList,hisObj));
				equityPriceObj.setPresident(getPresidentEquityValue(CoreWarnItemEnum.EQUITYPRICE.getKey(),detailList));
				equityPriceObj.setBefore(getEquityValue("before",priceList,hisObj));
				equityPriceObj.setAfter(getEquityValue("after",priceList,hisObj));
				equityPriceObj.setMarsVersion(coreMarsVersion);
				equityPriceObj.setStrategyIsEdit(false);
				equityPriceObj.setPresidentIsEdit(true);
				equityPriceObj.setBeforeIsEdit(true);
				equityPriceObj.setAfterIsEdit(true);
				coreWarnInfoList.add(equityPriceObj);
				if(hisObj != null) {
					prepareHisCoreWarnInfo(coreWarnInfoList,hisObj);
				}else {
					initCoreWarnInfo(CoreWarnItemEnum.EQUITYBEFOREPROFIT.getKey(),coreWarnInfoList,detailList,investmentResult,coreWarnId++,coreMarsVersion);
					initCoreWarnInfo(CoreWarnItemEnum.EQUITYAFTERPROFIT.getKey(),coreWarnInfoList,detailList,investmentResult,coreWarnId++,coreMarsVersion);
					initCoreWarnInfo(CoreWarnItemEnum.CREATEPROFIT.getKey(),coreWarnInfoList,detailList,investmentResult,coreWarnId++,coreMarsVersion);
					initCoreWarnInfo(CoreWarnItemEnum.MELTINGIRR.getKey(),coreWarnInfoList,detailList,investmentResult,coreWarnId++,coreMarsVersion);
					initCoreWarnInfo(CoreWarnItemEnum.MELTINGINVESTMENT.getKey(),coreWarnInfoList,detailList,investmentResult,coreWarnId++,coreMarsVersion);
				}
				vo.setCoreWarnInfoList(coreWarnInfoList);
				//########################本次调价对整盘核心指标影响###############################################
				
				//########################预警简报###############################################
				List<BulletinWarnInfoVO> bulletinWarnInfoList = new ArrayList<>();
				if(hisObj != null) {
					BulletinWarnInfoVO hisBulletinVo = prepareBulletinWarnInfo(hisObj);
					if(hisBulletinVo == null) {
						initBulletinWarnInfo(bulletinWarnInfoList);
					}else {
						bulletinWarnInfoList.add(hisBulletinVo);
					}
				}
				prepareBulletinBuildWarn(bulletinWarnInfoList,bulidAvgDifferenceList);
				vo.setBulletinWarnInfo(bulletinWarnInfoList);
				//########################预警简报###############################################
			
				//########################项目背景与价格策略###############################################
				if(hisObj != null) {
					 List<BackTacticsWarnInfoVO> backTacticsWarnInfoList = hisObj.getBackTacticsWarnInfoList();
					 vo.setBackTacticsWarnInfoList(backTacticsWarnInfoList);
				}else {
					int backWarnId = 0;
					List<BackTacticsWarnInfoVO> backTacticsWarnInfoList = new ArrayList<>();
					initBackTactics(BackTacticsEnum.PROJECTINFO.getKey(),backTacticsWarnInfoList,backWarnId++);
					initBackTactics(BackTacticsEnum.RISKASSESSMENT.getKey(),backTacticsWarnInfoList,backWarnId++);
					initBackTactics(BackTacticsEnum.PRICESTRATEGYDESC.getKey(),backTacticsWarnInfoList,backWarnId++);
					initBackTactics(BackTacticsEnum.PRICEADJUSTDESC.getKey(),backTacticsWarnInfoList,backWarnId++);
					initBackTactics(BackTacticsEnum.OTHER.getKey(),backTacticsWarnInfoList,backWarnId++);
					vo.setBackTacticsWarnInfoList(backTacticsWarnInfoList);
				}
				//########################项目背景与价格策略###############################################
			}
		}else {
			String content = approvalPreviewMapper.selectWarnContentByBillId(businessKey);
			if(StrUtils.isNotEmpty(content)) {
				vo = JSON.parseObject(content, PriceApproveWarnInfoVO.class);
			}
		}
		return vo;
	}
	//获取权益前投资数据
	private String getInvestmentValue(String type,String investmentlossResult,PriceApproveWarnInfoVO hisVo,CoreWarnInfoVO equityPriceObj) {
		String hisRes = "";
		String curRes = "";
		if(hisVo != null) {
			List<CoreWarnInfoVO> coreWarnList = hisVo.getCoreWarnInfoList().stream().filter(x-> x.getType().equals(CoreWarnItemEnum.EQUITYPRICE.getKey()) ).collect(Collectors.toList());
			if(CollectionUtils.isNotEmpty(coreWarnList)) {
				for(CoreWarnInfoVO vo : coreWarnList) {
					hisRes = vo.getInvestment();
				}
			}
		}
		
		if(StrUtils.isNotEmpty(investmentlossResult)) {
			JSONObject obj =  JSON.parseObject(investmentlossResult);
			JSONArray arr = obj.getJSONArray("retData");
			if(arr != null && arr.size() > 0) {
				for(int i =0; i < arr.size(); i++) {
					JSONObject  dataObj = arr.getJSONObject(i);
					curRes = MathUtils.formatWan(StrUtils.isEmpty(dataObj.getString("totalPriceInv")) ? null : new BigDecimal(dataObj.getString("totalPriceInv")));
				}
			}
		}
		
		if(StrUtils.isEmpty(curRes)) {
			equityPriceObj.setInvestmentIsEdit(false);
			return hisRes;
		}else {
			equityPriceObj.setInvestmentIsEdit(true);
			return curRes;
		}
	}
	
	//获取其他投资版数据
	private String getOtherInvestmentValue(String type,String investmentlossResult) {
		if(StrUtils.isNotEmpty(investmentlossResult)) {
			JSONObject obj =  JSON.parseObject(investmentlossResult);
			JSONArray arr = obj.getJSONArray("retData");
			if(arr != null && arr.size() > 0) {
				for(int i = 0 ; i< arr.size();i++) {
					JSONObject  dataObj = arr.getJSONObject(i);
					if(type.equals(CoreWarnItemEnum.MELTINGIRR.getKey())){
						return dataObj.getString("intlRateInv");
					}else if(type.equals(CoreWarnItemEnum.MELTINGINVESTMENT.getKey())){
						return dataObj.getString("staPbkFinancInv");
					}else if(type.equals(CoreWarnItemEnum.CREATEPROFIT.getKey())){
						return dataObj.getString("xhRateInv");
					}else {
						return "";
					}
				}
			}
		}
		return "";
	}
	

	//楼栋均价，调整前不等于调整后
	private boolean compareBuildAvgDiff(BulidWarnInfoVO vo) {
		if(StrUtils.isEmpty(vo.getBeforeAvg())) {
			return true;
		}
		if(StrUtils.isNotEmpty(vo.getBeforeAvg()) && StrUtils.isNotEmpty(vo.getAfterAvg())
				&& new BigDecimal(vo.getAfterAvg()).compareTo(new BigDecimal(vo.getBeforeAvg())) != 0 ) {
			return true;
		}
		return false;
	}
	
	//是否可编辑楼栋
	private boolean isEdit(String val) {
		if(StrUtils.isNotEmpty(val) && val.equals("true")) {
			return true;
		}
		return false;
	}
	
	/**
	 * 计算楼栋均价偏离度并设置其对标版本
	 */
	private String calculateBuildAvgDivergeRate(BulidWarnInfoVO obj,String afterAvg,String groupAvg,String strategyAvg) {
		String result = "";
		String compareAvg = "";
		if(StrUtils.isEmpty(groupAvg)) {
			if(StrUtils.isNotEmpty(strategyAvg)) {
				compareAvg = strategyAvg;
				obj.setMarsVersion("战规版");
			}
		}else {
			compareAvg = groupAvg;
			obj.setMarsVersion("集团审批版");
		}
		if(StrUtils.isNotEmpty(afterAvg) && StrUtils.isNotEmpty(compareAvg)) {
			BigDecimal b1 = new BigDecimal(afterAvg);
			BigDecimal b2 = new BigDecimal(compareAvg);
			if(b2.compareTo(BigDecimal.ZERO) != 0) {
				BigDecimal subVal = b1.subtract(b2);
				result = subVal.divide(b2, 4, BigDecimal.ROUND_HALF_UP).toString();
			}
		}
		return result;
	}

	private BulletinWarnInfoVO prepareBulletinWarnInfo(PriceApproveWarnInfoVO hisVo) {
		List<BulletinWarnInfoVO> bulletinWarnInfo = hisVo.getBulletinWarnInfo();
		if(CollectionUtils.isNotEmpty(bulletinWarnInfo)) {
			return bulletinWarnInfo.get(0);
		}
		return null;
	}
	
	private void prepareHisCoreWarnInfo(List<CoreWarnInfoVO> coreWarnInfoList, PriceApproveWarnInfoVO hisVo) {
		List<CoreWarnInfoVO> coreWarnList = hisVo.getCoreWarnInfoList().stream().filter(x-> !x.getType().equals(CoreWarnItemEnum.EQUITYPRICE.getKey()) ).collect(Collectors.toList());
		if(CollectionUtils.isNotEmpty(coreWarnList)) {
			for(CoreWarnInfoVO vo : coreWarnList) {
				vo.setInvestmentIsEdit(false);
				vo.setStrategyIsEdit(false);
				vo.setPresidentIsEdit(true);
				vo.setCheckIsEdit(false);
				vo.setBeforeIsEdit(false);
				vo.setAfterIsEdit(false);
			}
		}
		coreWarnInfoList.addAll(coreWarnList);
	}
	
	private void initBulletinWarnInfo(List<BulletinWarnInfoVO> bulletinWarnInfoList) {
		BulletinWarnInfoVO bulletinWarnInfoVO = new BulletinWarnInfoVO();
		bulletinWarnInfoVO.setId(1);
		bulletinWarnInfoList.add(bulletinWarnInfoVO);
	}
	
	/*
	 * 楼栋均价货值预警简报  
	 * 存在一个楼栋的均价偏离度的绝对值大于等于 3% 时，触发楼栋均价偏离度预警； 
	 * 如果所有楼栋的均价偏离度都正向偏离，不管是否大于等于 3% ，不触发楼栋均价偏离度预警；
	 */
	private void prepareBulletinBuildWarn(List<BulletinWarnInfoVO> bulletinWarnInfoList,List<BulidWarnInfoVO> bulidWarnInfoList) {
		if(CollectionUtils.isNotEmpty(bulidWarnInfoList)) {
			BulletinWarnInfoVO bulletinWarnInfoVO = new BulletinWarnInfoVO();
			boolean isAllPositiveDeviation = isAllPositiveDeviation(bulidWarnInfoList);
			String marsVersion = bulidWarnInfoList.get(0).getMarsVersion();
 			if(!isAllPositiveDeviation) {//全部正向偏离
				bulletinWarnInfoVO.setId(1);
				bulletinWarnInfoVO.setStatus("success");
				bulletinWarnInfoVO.setType(StrUtils.isEmpty(marsVersion) ? "楼栋均价无对标版本" :"楼栋均价与"+marsVersion+"相比，偏离度全部正向偏离");
				bulletinWarnInfoVO.setContent("");
				bulletinWarnInfoVO.setContrastType(marsVersion);
			}else {
				List<BulidWarnInfoVO> bulidWarnList = bulidWarnInfoList.stream().filter(s-> buildDivergeRateWarn(s.getDivergeRate())).collect(Collectors.toList());
				if(CollectionUtils.isNotEmpty(bulidWarnList)) {
					bulletinWarnInfoVO.setId(1);
					bulletinWarnInfoVO.setStatus("warning");
					bulletinWarnInfoVO.setType("调整后楼栋均价与"+marsVersion+"相比，偏离度增加或降低超过3%");
					bulletinWarnInfoVO.setContent(prepareBuildAvgWarnContent(bulidWarnList));
					bulletinWarnInfoVO.setContrastType(marsVersion);
				}else {
					bulletinWarnInfoVO.setId(1);
					bulletinWarnInfoVO.setStatus("success");
					bulletinWarnInfoVO.setType(StrUtils.isEmpty(marsVersion) ? "楼栋均价无对标版本" :"楼栋均价与"+marsVersion+"相比，偏离度增加或降低未超过3%");
					bulletinWarnInfoVO.setContent("");
					bulletinWarnInfoVO.setContrastType(marsVersion);
				}
			}
 			bulletinWarnInfoList.add(bulletinWarnInfoVO);
		}
	}
	//楼栋偏离度预警判断
	private boolean buildDivergeRateWarn(String value) {
		if(StrUtils.isNotEmpty(value)) {
			List<ApprovalWarningPosition> warningPositionList = approvalWarningMapper.selectByType(WarnPossitionTypeEnum.THRESHOLD_VALUE.getKey());
			BigDecimal thresholdValue = new BigDecimal(warningPositionList.get(0).getPositionNum());
			BigDecimal bValue = new BigDecimal(value);
			if(bValue.abs().compareTo(thresholdValue) >=0) {
				return true;
			}
		}
		return false;
	}
	
	//判断楼栋均价是否全部正向偏离
	private boolean isAllPositiveDeviation(List<BulidWarnInfoVO> bulidWarnInfoList) {
		for(BulidWarnInfoVO vo :  bulidWarnInfoList) {
			if(StrUtils.isNotEmpty(vo.getDivergeRate())) {
				BigDecimal bValue = new BigDecimal(vo.getDivergeRate());
				if(bValue.compareTo(BigDecimal.ZERO) < 0) {
					return true;
				}
			}
		}
		return false;
	}
	
	//楼栋均价预警简报详情
	private String prepareBuildAvgWarnContent(List<BulidWarnInfoVO> bulidWarnList) {
		StringBuilder sb = new StringBuilder();
		String marsVersion = bulidWarnList.get(0).getMarsVersion();
		if(CollectionUtils.isNotEmpty(bulidWarnList)) {
			for(BulidWarnInfoVO vo : bulidWarnList) {
				String avg ="";
				if(marsVersion.equals("战规版")) {
					avg = vo.getStrategyAvg();
				}else  {
					avg = vo.getPresidentAvg();
				}
				sb.append(vo.getObjectName()).append("，")
				.append(marsVersion).append("楼栋均价 ")
				.append(MathUtils.roundNum(avg))
				.append(getUnit(vo.getIsParking()))
				.append("本次调整后楼栋均价为")
				.append(MathUtils.roundNum(vo.getAfterAvg()))
				.append(getUnit(vo.getIsParking()))
				.append("均价偏离度")
				.append(MathUtils.decimalFormat(vo.getDivergeRate()))
				.append(";<br>");
			}
		}
		return sb.toString();
	}
	
	private String getUnit(Integer isParking) {
		if(isParking.intValue() == WhetherEnum.YES.getKey()) {
			return "元/个，";
		}else {
			return "元/平米，";
		}
	}
	
	private String getEquityValue(String key,List<EquityValueDto> priceList,PriceApproveWarnInfoVO hisVo) {
		String result = "";
		if(key.equals("strategy")) {
			if(hisVo != null) {
				List<CoreWarnInfoVO> coreWarnList = hisVo.getCoreWarnInfoList().stream().filter(x-> x.getType().equals(CoreWarnItemEnum.EQUITYPRICE.getKey()) ).collect(Collectors.toList());
				if(CollectionUtils.isNotEmpty(coreWarnList)) {
					for(CoreWarnInfoVO vo : coreWarnList) {
						result = vo.getStrategy();
					}
				}
			}
			if(StrUtils.isEmpty(result)) {
				if(CollectionUtils.isNotEmpty(priceList)) {
					for(EquityValueDto dto : priceList) {
						if(key.equals(dto.getType()) && dto.getPrice() != null) {
							return MathUtils.formatWan(dto.getPrice());
						}
					}
				}
			}
		}else {
			if(CollectionUtils.isNotEmpty(priceList)) {
				for(EquityValueDto dto : priceList) {
					if(key.equals(dto.getType()) && dto.getPrice() != null) {
						return MathUtils.formatWan(dto.getPrice());
					}
				}
			}
		}
		return result;
	}
	
	private String getPresidentEquityValue(String key,List<PriceCoreDetailDTO> detailList) {
		String result = "";
		if(CollectionUtils.isNotEmpty(detailList)) {
			for(PriceCoreDetailDTO dto : detailList) {
				if(key.equals(dto.getType()) && dto.getAfter() != null) {
					return dto.getAfter() != null ? String.valueOf(dto.getAfter()) : "";
				}
			}
		}
		return result;
	}
	
	private void initBackTactics(String type,List<BackTacticsWarnInfoVO> backTacticsWarnInfoList,int id) {
		BackTacticsWarnInfoVO vo = new BackTacticsWarnInfoVO();
		vo.setId(id);
		vo.setItem(type);
		vo.setItemName(BackTacticsEnum.getValueByKey(type));
		backTacticsWarnInfoList.add(vo);
	}
	
	private void initCoreWarnInfo(String type,List<CoreWarnInfoVO> coreWarnInfoList,List<PriceCoreDetailDTO> detailList,
			String investmentResult,int id,String coreMarsVersion) {
		CoreWarnInfoVO vo = new CoreWarnInfoVO();
		vo.setId(id);
		vo.setType(type);
		vo.setName(CoreWarnItemEnum.getValueByKey(type));
		vo.setPresident(getPresidentEquityValue(type,detailList));
		vo.setInvestment(getOtherInvestmentValue(type,investmentResult));
		if(StrUtils.isEmpty(getOtherInvestmentValue(type,investmentResult))) {
			vo.setInvestmentIsEdit(false);
		}else {
			vo.setInvestmentIsEdit(true);
		}
		vo.setStrategyIsEdit(false);
		vo.setPresidentIsEdit(true);
		vo.setBeforeIsEdit(false);
		vo.setAfterIsEdit(false);
		vo.setMarsVersion(coreMarsVersion);
		coreWarnInfoList.add(vo);
	}
	
	private String getBalance(String v1,String v2) {
		String result = "";
		if(StrUtils.isNotEmpty(v1) && StrUtils.isNotEmpty(v2)) {
			BigDecimal b1 = new BigDecimal(v1);
			BigDecimal b2 = new BigDecimal(v2);
			result = b1.subtract(b2).toString();
		}
		return result;
	}
    
	private String getPriceAvg(String stageId,String buildId,Map<String, List<PriceValueDto>> bulidMap) {
		String result = "";
		if(bulidMap != null && !bulidMap.isEmpty() ) {
			for(Map.Entry<String,List<PriceValueDto>> entry:bulidMap.entrySet()){
	            if(stageId.equals(entry.getKey())) {
	            	List<PriceValueDto> list = entry.getValue();
	            	for(PriceValueDto dto : list) {
	            		if(buildId.equals(dto.getBuildId())) {
	            			result = String.valueOf(dto.getAvg());
	            		}
	            	}
	            }
			}
		}
		return result;
	}

	@Override
	public void cleanPriceWarnTodo(String billId, IdmUser user) {
		ApprovalWarning obj = approvalWarningMapper.selectByBillId(billId);
		if(obj != null) {
			String taskId = obj.getTaskId();
			if(StrUtils.isNotEmpty(taskId)) {
				String[] arr = taskId.split(";");
				for(String instanceId : arr) {
					commonService.cleanTodo(TodoTypeCodeEnum.WARNING_SUPERVISE.getKey(),OperatorTypeEnum.DELETE.getKey(),null,instanceId,user);
				}
			}
		}
	}

}
